package com.abcode.nettyserversocketio.biz.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTHeader;
import cn.hutool.jwt.JWTUtil;
import com.abcode.nettyserversocketio.biz.IUserBizService;
import com.abcode.nettyserversocketio.common.Result;
import com.abcode.nettyserversocketio.common.utils.BuildUtil;
import com.abcode.nettyserversocketio.gen.entity.FriendRequest;
import com.abcode.nettyserversocketio.gen.entity.User;
import com.abcode.nettyserversocketio.gen.entity.UserRelation;
import com.abcode.nettyserversocketio.gen.param.UserParam;
import com.abcode.nettyserversocketio.gen.service.FriendRequestService;
import com.abcode.nettyserversocketio.gen.service.UserRelationService;
import com.abcode.nettyserversocketio.gen.service.UserService;
import com.abcode.nettyserversocketio.gen.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户相关接口实现类
 */
@Service
public class UserBizServiceImpl implements IUserBizService {

    @Resource
    UserService userService;
    @Resource
    UserRelationService userRelationService;
    @Resource
    FriendRequestService friendRequestService;

    @Value("${biz.jwt.key}")
    String jwtKey;
    @Value("${biz.jwt.life-time}")
    int lifeTime;

    @Override
    public Result reg(UserParam userParam) {
        String username = userParam.getUsername();

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        Long count = userService.count(queryWrapper);
        if(count >0){
            return Result.error("用户名已存在");
        }
        User user = BuildUtil.buildUser(userParam);
        String uuid = RandomUtil.randomNumbers(8);
        boolean checkRst = checkUuid(uuid);
        if(!checkRst){
            throw new RuntimeException("服务器繁忙，请稍后重试。");
        }
        user.setProfile("default.png");
        user.setSign("这个人不懒，但什么都没有写。");
        user.setNickName(username);
        user.setUuid(uuid);
        boolean rst = userService.save(user);
        return Result.OK().success("注册成功");
    }

    /**
     * 判断uuid是否可用
     * @param uuid
     * @return
     */
    private boolean checkUuid(String uuid) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUuid, uuid);
        long count = userService.count(queryWrapper);
        return count == 0;
    }

    @Override
    public Result login(UserParam userParam) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userParam.getUsername());
        User user = userService.getOne(queryWrapper);
        if(ObjUtil.isNull(user)){
            return Result.error("用户名不正确");
        }
        String pwdMd5 = SecureUtil.md5(userParam.getPassword());
        if(!StrUtil.equals(pwdMd5, user.getPassword())){
            return Result.error("密码不正确");
        }

        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);

        Map<String,Object> dataMap = MapUtil.newHashMap();
        dataMap.put("user", userVO);
        dataMap.put("expireTime", System.currentTimeMillis()+lifeTime*60*60*1000);
        String token = JWTUtil.createToken(dataMap, jwtKey.getBytes());
        System.out.println("token: " + token);
        userVO.setToken(token);
        return Result.ok(userVO);
    }

    @Override
    public Result verifyToken(String token) {
        final JWT jwt = JWTUtil.parseToken(token);
        Object jwtHeaderType = jwt.getHeader(JWTHeader.TYPE);
        Object obj = jwt.getPayload("user");
        System.out.println("Authorization: " + token);
        boolean rst = JWTUtil.verify(token, jwtKey.getBytes());
        if(rst){
            return Result.ok();
        }
        return Result.error("Token无效！");
    }

    @Override
    public UserVO getUserVOByToken(String token) {
        if(StrUtil.isBlank(token)){
           throw new RuntimeException("token 异常，不应该为null");
        }
        boolean rst = JWTUtil.verify(token, jwtKey.getBytes());
        if(rst){
            final JWT jwt = JWTUtil.parseToken(token);
            Object obj = jwt.getPayload("user");
            UserVO userVO = JSONUtil.toBean(JSONUtil.parse(obj).toString(), UserVO.class);
            return userVO;
        }
        return null;
    }

    @Override
    public List<User> getAllFriends(Long id) {
        List<User> resultList = Arrays.asList();
        LambdaQueryWrapper<UserRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRelation::getUserId, id).or().eq(UserRelation::getRelationId, id);
        List<UserRelation>  relationList = userRelationService.list(queryWrapper);
        if(ObjUtil.isNotEmpty(relationList)){
            List<Long> relationIdList = new ArrayList<>();
            for (UserRelation userRelation : relationList) {
                Long relationId = userRelation.getRelationId();
                if(relationId.equals(id)){
                    relationIdList.add(userRelation.getUserId());
                }else{
                    relationIdList.add(relationId);
                }
            }
            resultList = userService.listByIds(relationIdList);
        }
        return resultList;
    }

    @Override
    public List<User> selectUser(String uuid) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(User::getUuid, uuid);
        return userService.list(queryWrapper);
    }

    @Override
    public boolean isOwnFriend(Long userId, Long relationId) {

        LambdaQueryWrapper<UserRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(wrapper-> wrapper.eq(UserRelation::getUserId, userId).eq(UserRelation::getRelationId, relationId));
        queryWrapper.or(wrapper-> wrapper.eq(UserRelation::getUserId, relationId).eq(UserRelation::getRelationId, userId));

        long count = userRelationService.count(queryWrapper);
        return count >0;
    }

    @Override
    public boolean addFriend(Long id, String uuid) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUuid, uuid);
        User user = userService.getOne(queryWrapper);
        if(ObjUtil.isNotEmpty(user)){

            LambdaQueryWrapper<UserRelation> relationWrapper = new LambdaQueryWrapper<>();
            relationWrapper.and(wrapper-> wrapper.eq(UserRelation::getUserId, id).eq(UserRelation::getRelationId, user.getId()));
            relationWrapper.or(wrapper-> wrapper.eq(UserRelation::getUserId, user.getId()).eq(UserRelation::getRelationId, id));
            long count = userRelationService.count(relationWrapper);
            if(count == 0){
                UserRelation relation = new UserRelation();
                relation.setUserId(id);
                relation.setRelationId(user.getId());
                relation.setNickName(user.getNickName());
                relation.setCreateTime(DateUtil.date());

                return userRelationService.save(relation);
            }
        }
        return false;
    }

    @Override
    public boolean friendRequest(UserVO fromUser, Long toUserId, String message) {

        User toUser = userService.getById(toUserId);
        if(ObjUtil.isNotEmpty(toUser)){
            
            LambdaQueryWrapper<UserRelation> relationWrapper = new LambdaQueryWrapper<>();
            relationWrapper.and(wrapper-> wrapper.eq(UserRelation::getUserId, fromUser.getId()).eq(UserRelation::getRelationId, toUser.getId()));
            relationWrapper.or(wrapper-> wrapper.eq(UserRelation::getUserId, toUser.getId()).eq(UserRelation::getRelationId, fromUser.getId()));
            long count = userRelationService.count(relationWrapper);
            if(count == 0){
                FriendRequest friendRequest = new FriendRequest();
                friendRequest.setFromUserId(fromUser.getId());
                friendRequest.setToUserId(toUserId);
                friendRequest.setFromNickName(fromUser.getNickName());
                friendRequest.setRequestMsg(message);
                // TODO: 2023/6/19 添加枚举 
                friendRequest.setRequestStatus(0);
                friendRequest.setReadStatus(0);
                friendRequest.setProcessTime(DateUtil.date());
                friendRequest.setCreateTime(DateUtil.date());

                return friendRequestService.save(friendRequest);
            }
        }
        return false;
    }

    @Override
    public int getAllNoticesNumber(Long toUserId) {
        LambdaQueryWrapper<FriendRequest> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FriendRequest::getToUserId, toUserId);
        // TODO: 2023/6/20 应使用枚举
        queryWrapper.eq(FriendRequest::getReadStatus, 0);
        Long count = friendRequestService.count(queryWrapper);
        return Math.toIntExact(count);
    }

    @Override
    public List<FriendRequest> getAllNotices(Long toUserId) {
        LambdaQueryWrapper<FriendRequest> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FriendRequest::getToUserId, toUserId);
        // TODO: 2023/6/20 应使用枚举
        queryWrapper.eq(FriendRequest::getReadStatus, 0);
        List<FriendRequest> list = friendRequestService.list(queryWrapper);
       return  list;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result agreeFriendRequest(UserVO userVO, Long friendRequestId) {

        FriendRequest friendRequest = friendRequestService.getById(friendRequestId);

        //更新请求状态
        LambdaUpdateWrapper<FriendRequest> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(FriendRequest::getId, friendRequest.getId());
        // TODO: 2023/6/24 枚举
        updateWrapper.eq(FriendRequest::getRequestStatus, 0);

        updateWrapper.set(FriendRequest::getRequestStatus, 1);
        updateWrapper.set(FriendRequest::getUpdateTime, DateUtil.date());
        updateWrapper.set(FriendRequest::getReadStatus, 1);
        updateWrapper.set(FriendRequest::getProcessTime, DateUtil.date());

        boolean updateRst = friendRequestService.update(updateWrapper);
        if(!updateRst){
            return Result.error("申请状态有更新，你刷新页面");
        }
        //添加好友关第
        if(!isOwnFriend(friendRequest.getFromUserId(), userVO.getId())){
            UserRelation userRelation = new UserRelation();
            userRelation.setUserId(friendRequest.getFromUserId());
            userRelation.setRelationId(userVO.getId());
            userRelation.setNickName(userVO.getNickName());
            userRelation.setCreateTime(DateUtil.date());

            userRelationService.save(userRelation);

        }
        return Result.ok("已添加为好友，快去打招呼");
    }

    /**
     * 根据唯一标识获取用户信息
     * @param uuid 用户唯一编号
     * @return
     */
    public User getUserByUuid(String uuid){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUuid, uuid);
        User user = userService.getOne(queryWrapper);
        return user;
    }
}
